
#include "NodeInfo.h"

using namespace std;
using namespace ttg;
using namespace ttg::extras;
using namespace ttg::structures;
using namespace ttg::strings;
using namespace ttg_internal::pipeline;

//----------------
//--- NodeInfo ---
//----------------

NodeInfo::NodeInfo(const char *name, bool isSingleThreaded, bool isProxy)
	:NamedObject(name)
{
	filter = NULL;
	this->is_proxy = isProxy;
	this->is_single_threaded = isSingleThreaded;
	this->dif_abstract = NULL;
	this->dif_time = NULL;
	this->coeff = 1.0f;
#ifdef TTG_PL_VISUALIZER
	this->cpu_usage = NULL;
	this->frame_time = 0.0f;
	this->task_count = NULL;
	this->active_task_count = NULL;
#endif
}

void NodeInfo::bind(ttg::utils::ParameterSet *owner)
{
	filter = new ttg::utils::ParameterSet(getName(), owner);
#ifdef TTG_PL_VISUALIZER
	task_count = new ttg::utils::Parameter<int>("Task count", filter);
	task_count->setReadOnly(true);
	active_task_count = new ttg::utils::Parameter<int>("Active task count", filter);
	active_task_count->setReadOnly(true);
#endif
	dif_abstract = new ttg::utils::Parameter<double>("Abstract difficulty", filter);
	dif_abstract->setReadOnly(true);
	dif_time = new ttg::utils::Parameter<double>("Time difficulty", filter);
	dif_time->setReadOnly(true);
#ifdef TTG_PL_VISUALIZER
	cpu_usage = new ttg::utils::Parameter<double>("Usage", filter);
	cpu_usage->setReadOnly(true);
#endif
}

void NodeInfo::unBind()
{
#ifdef TTG_PL_VISUALIZER
	SAFE_DELETE(cpu_usage);
	SAFE_DELETE(task_count);
	SAFE_DELETE(active_task_count);
#endif
	SAFE_DELETE(dif_time);
	SAFE_DELETE(dif_abstract);
	SAFE_DELETE(filter);
}

#ifdef TTG_PL_VISUALIZER
void NodeInfo::setTimes(double frame_time, double summed_time)
{
	this->frame_time = frame_time;
	if (*cpu_usage != 0.0)
		for (size_t i = 0; i < thread_usage.size(); i++)
			thread_usage[i] = thread_usage[i] / *cpu_usage * 100.0;
	if (frame_time != 0.0 && thread_usage.size() != 0)
		*cpu_usage = *dif_time / (frame_time * thread_usage.size()) * 1000.0 * 100.0;
	else
		*cpu_usage = 0.0;
}

void NodeInfo::store(XMLTree &xml, Enumerator<NodeInfo *> &nodes)
{
	xml.addSectionAndOpen("Nodes");
	nodes.reset();
	while (nodes.moveNext())
	{
		NodeInfo *cur = nodes.current();
		xml.addSectionAndOpen("Node");
		//Adding common.
		xml.addStringAttribute("name", cur->getName());
		xml.addDoubleAttribute("dif_abstract", *cur->dif_abstract);
		xml.addDoubleAttribute("dif_time", *cur->dif_time);
		xml.addDoubleAttribute("coeff", cur->coeff);
		xml.addBoolAttribute("is_proxy", cur->is_proxy);
		xml.addBoolAttribute("is_single_threaded", cur->is_single_threaded);
		//Adding statistics.
		xml.addDoubleAttribute("cpu_usage", *cur->cpu_usage);
		xml.addDoubleAttribute("frame_time", cur->frame_time);
		xml.addIntAttribute("task_count", *cur->task_count);
		//Adding thread usage.
		xml.addSectionAndOpen("Threads");
		for (size_t i = 0; i < cur->thread_usage.size(); i++)
			xml.addDoubleAttribute("thread", cur->thread_usage[i]);
		xml.closeSection();
		//Adding references to next nodes.
		xml.addSectionAndOpen("Next");
		for (size_t i = 0; i < cur->next.size(); i++)
			xml.addStringAttribute("node", cur->next[i]->getName());
		xml.closeSection();
		xml.closeSection();
	}
	xml.closeSection();
}

Dictionary<NodeInfo> *NodeInfo::create(XMLTree &xml)
{
	Dictionary<NodeInfo> *res = Dictionary<NodeInfo>::create(xml.getSubSectionCount());
	//Loading all nodes.
	xml.resetIterators();
	while (xml.openNextSection())
	{
		//Creating empty node.
		const char *name;
		bool is_proxy;
		bool is_single_threaded;
		if (!xml.getStringAttribute("name", name) ||
			!xml.getBoolAttribute("is_proxy", is_proxy) ||
			!xml.getBoolAttribute("is_single_threaded", is_single_threaded))
			throw Error(Error::FATAL, "NodeInfo", "create",
						"Cannot find name of node or flags");
		string cleared_name = clearStartEndSpaces(name);
		NodeInfo *info = new NodeInfo(cleared_name.c_str(), is_proxy, is_single_threaded);
		double dif_time;
		double dif_abstract;
		double cpu_usage;
		int task_count;
		//Loading attributes.
		if (!xml.getDoubleAttribute("dif_abstract", dif_abstract) ||
			!xml.getDoubleAttribute("dif_time", dif_time) ||
			!xml.getDoubleAttribute("coeff", info->coeff) ||
			!xml.getDoubleAttribute("cpu_usage", cpu_usage) ||
			!xml.getDoubleAttribute("frame_time", info->frame_time) ||
			!xml.getIntAttribute("task_count", task_count))
			throw Error(Error::FATAL, "NodeInfo", "create",
						"Cannot find some attributes");
		*info->dif_time = dif_time;
		*info->dif_abstract = dif_abstract;
		*info->cpu_usage = cpu_usage;
		*info->task_count = task_count;
		*info->active_task_count = 0;
		//Loading thread usage.
		if (!xml.openSection("Threads"))
			throw Error(Error::FATAL, "NodeInfo", "create",
						"Cannot find \"Threads\" section");
		const char *attr_name;
		const char *attr_value;
		xml.resetIterators();
		while (xml.getNextAttribute(attr_name, attr_value))
		{
			double val = 0.0;
			string cleared_value = clearStartEndSpaces(attr_value);
			isFloat(cleared_value.c_str(), val);
			info->thread_usage.push_back(val);
		}
		xml.closeSection();
		//Loading next nodes.
		if (xml.openSection("Next"))
		{
			xml.resetIterators();
			while (xml.getNextAttribute(attr_name, attr_value))
			{
				cleared_name = clearStartEndSpaces(attr_value);
				info->next.push_back(new NodeInfo(cleared_name.c_str(), false, false));	//adding stub
			}
			xml.closeSection();
		}
		xml.closeSection();
		res->add(info);
	}
	//Linking nodes.
	list<NodeInfo *> en = res->toList();
	list<NodeInfo *>::iterator it = en.begin();
	while (it != en.end())
	{
		NodeInfo *cur = *it;
		for (size_t i = 0; i < cur->next.size(); i++)
		{
			NodeInfo *ref = res->get(cur->next[i]->getName());
			if (ref == NULL)
				throw Error(Error::FATAL, "NodeInfo", "create",
							"Cannot find node", cur->next[i]->getName());
			SAFE_DELETE(cur->next[i]);
			cur->next[i] = ref;
		}
		it++;
	}
	return res;
}

#endif
